package cn.shujuhai.meeting.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.shujuhai.common.domain.Department;
import cn.shujuhai.common.domain.DepartmentMeet;
import cn.shujuhai.common.mapper.SysUserMapper;
import cn.shujuhai.common.pluging.data.ResultCode;
import cn.shujuhai.common.pluging.data.ResultVo;
import cn.shujuhai.common.pluging.file.FilesUtils;
import cn.shujuhai.common.service.DepartmentMeetService;
import cn.shujuhai.common.service.DepartmentService;
import cn.shujuhai.common.service.SysUserService;
import cn.shujuhai.meeting.domain.MeetCount;
import cn.shujuhai.meeting.domain.MeetReservation;
import cn.shujuhai.meeting.domain.MeetingRooms;
import cn.shujuhai.meeting.domain.Reservation;
import cn.shujuhai.meeting.mapper.MeetingRoomsMapper;
import cn.shujuhai.meeting.mapper.ReservationMapper;
import cn.shujuhai.meeting.service.MeetReservationService;
import cn.shujuhai.meeting.service.MeetingRoomsService;
import cn.shujuhai.meeting.service.ReservationService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 4g0
 * @description 针对表【meeting_rooms(会议室管理表，用于存储会议室的基本信息和状态)】的数据库操作Service实现
 * @createDate 2025-04-08 09:39:11
 */
@RequiredArgsConstructor
@Service
public class MeetingRoomsServiceImpl extends ServiceImpl<MeetingRoomsMapper, MeetingRooms>
        implements MeetingRoomsService {
    final DepartmentMeetService departmentMeetService;
    final DepartmentService departmentService;
    final SysUserMapper sysUserMapper;
    final CacheManager cacheManager;
    final TaskScheduler scheduler;
    final ReservationMapper reservationMapper;
    final MeetReservationService meetReservationService;
    final HttpServletRequest request;
    @Value("${template.static.meetingImageUrl}")
    public String UPLOADS_PATH;
    @Value("${template.static.viewMeetingImageUrl}")
    public String VIEW_PATH;

    /**
     * 查询会议室列表
     *
     * @param roomName 会议室名称
     * @param capacity 可容纳人数
     * @param page     页码
     * @param pageSize 每页显示的条数
     * @return 查询的会议室列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo<PageInfo<MeetingRooms>> getMeetingRoomsPageInfo(String roomName, String capacity, Long departmentId, Integer page, Integer pageSize) {
        // 获取当前登录用户的角色代码
        List<String> roleCodes = this.sysUserMapper.selectRoleCodesByUserId(StpUtil.getLoginIdAsLong());
        // 分页查询
        PageHelper.startPage(page, pageSize);
        QueryWrapper<MeetingRooms> queryWrapper = new QueryWrapper<>();

        // 如果当前用户不是admin，根据部门ID筛选会议室
        if (!roleCodes.contains("super_admin") && departmentId != null) {
            List<Long> roomIds = this.departmentMeetService.list(
                            new QueryWrapper<DepartmentMeet>().lambda()
                                    .eq(DepartmentMeet::getDepartmentId, departmentId)
                                    .select(DepartmentMeet::getRoomId)
                    ).stream()
                    .map(DepartmentMeet::getRoomId)
                    .collect(Collectors.toList());

            if (!roomIds.isEmpty()) {
                queryWrapper.in("room_id", roomIds);
            } else {
                // 如果没有会议室属于该部门，直接返回空结果
                PageInfo<MeetingRooms> emptyPageInfo = new PageInfo<>();
                emptyPageInfo.setList(Collections.emptyList());
                return ResultVo.success(emptyPageInfo);
            }
        }

        // 添加会议室名称和容量的模糊查询条件
        if (roomName != null && !roomName.isEmpty()) {
            queryWrapper.like("room_name", roomName);
        }
        if (capacity != null && !capacity.isEmpty()) {
            queryWrapper.like("capacity", capacity);
        }

        // 查询会议室列表并排序
        List<MeetingRooms> meetingRoomsList = this.list(queryWrapper.lambda().orderByDesc(MeetingRooms::getRoomId));

        // 查询部门信息并整合
        for (MeetingRooms meetingRooms : meetingRoomsList) {
            // 1. 通过中间表 DepartmentMeet 查询 departmentId
            DepartmentMeet departmentMeet = this.departmentMeetService.getOne(
                    new QueryWrapper<DepartmentMeet>().eq("room_id", meetingRooms.getRoomId())
            );

            if (!ObjectUtil.isEmpty(departmentMeet)) {
                // 2. 通过 departmentId 查询 Department 表获取部门名称
                Department department = this.departmentService.getOne(
                        new QueryWrapper<Department>().lambda().eq(Department::getDepartmentId, departmentMeet.getDepartmentId())
                );

                if (!ObjectUtil.isEmpty(department)) {
                    // 3. 设置部门名称到 meetingRooms 对象
                    meetingRooms.setDepartmentName(department.getDepartmentName());
                    meetingRooms.setDepartmentId(department.getDepartmentId());
                }
            }
        }

        PageInfo<MeetingRooms> meetingRoomsPageInfo = new PageInfo<>(meetingRoomsList);
        return ResultVo.success(meetingRoomsPageInfo);
    }

    /**
     * 新增会议室
     *
     * @param meetingRooms 新增会议室对象
     * @return 新增会议室对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo<?> add(MeetingRooms meetingRooms) {
        if (!this.save(meetingRooms)) {
            return ResultVo.failure(ResultCode.FAILED);
        }
        DepartmentMeet departmentMeet = new DepartmentMeet();
        departmentMeet.setRoomId(Long.valueOf(meetingRooms.getRoomId()));
        departmentMeet.setDepartmentId(meetingRooms.getDepartmentId());
        if (!this.departmentMeetService.save(departmentMeet)) {
            return ResultVo.failure(ResultCode.FAILED);
        }
        return ResultVo.success();
    }

    /**
     * 会议室编辑
     *
     * @param meetingRooms 编辑会议室对象
     * @return 更新会议室对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo<MeetingRooms> edit(MeetingRooms meetingRooms) {
        if (!this.updateById(meetingRooms)) {
            return ResultVo.failure(ResultCode.FAILED);
        }
        DepartmentMeet departmentMeet = this.departmentMeetService.getOne(new QueryWrapper<DepartmentMeet>().eq("room_id", meetingRooms.getRoomId()));
        // 如果 departmentMeet 为空，创建一个新的对象
        if (BeanUtil.isEmpty(departmentMeet)) {
            departmentMeet = new DepartmentMeet();
            departmentMeet.setRoomId(meetingRooms.getRoomId());
            departmentMeet.setDepartmentId(meetingRooms.getDepartmentId());
            // 插入新记录
            if (!this.departmentMeetService.save(departmentMeet)) {
                return ResultVo.failure(ResultCode.FAILED);
            }
        } else {
            // 如果 departmentMeet 不为空，更新现有记录
            departmentMeet.setDepartmentId(meetingRooms.getDepartmentId());
            if (!this.departmentMeetService.updateById(departmentMeet)) {
                return ResultVo.failure(ResultCode.FAILED);
            }
        }
        return ResultVo.success();
    }

    /**
     * 删除会议室
     *
     * @param roomId 会议室Id
     * @return 删除响应结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo<MeetingRooms> removeId(Integer roomId) {
        this.departmentMeetService.remove(new QueryWrapper<DepartmentMeet>().lambda().eq(DepartmentMeet::getRoomId, roomId));
        if (!this.removeById(roomId)) {
            return ResultVo.failure(ResultCode.FAILED);
        }
        return ResultVo.success();
    }

    @Override
    public void updateMeetingRoomStatus(Integer roomId, String newStatus) {
        MeetingRooms rooms = this.getById(roomId);
        rooms.setStatus(newStatus);
        this.save(rooms);
    }

    @Override
    public ResultVo<?> uploadImage(MultipartFile file) {
        Cache cache = cacheManager.getCache("sys_setting");
        if (cache == null) {
            throw new IllegalStateException("未获取到缓存");
        }
        String s = cache.get("AVATAR_SIZE", String.class);
        s = StrUtil.trim(s);
        int avatarSize = StrUtil.isNotEmpty(s) ? Integer.parseInt(s) : 2048;
        if (file.getSize() > avatarSize * 1024L) {
            return ResultVo.failure("用户上传的头像大小不能超过" + avatarSize + "kb");
        }
        return ResultVo.success(FilesUtils.uploadFile(file, UPLOADS_PATH, VIEW_PATH));
    }

    @Override
    public ResultVo<?> getMeetingRoomById(Long roomId) {
        return ResultVo.success(this.getById(roomId));
    }

    @Override
    public void scheduleRoom(Long roomId, LocalDateTime start, LocalDateTime end) {
        // 开始时间 → 关
        scheduler.schedule(() -> this.lambdaUpdate()
                        .eq(MeetingRooms::getRoomId, roomId)
                        .set(MeetingRooms::getStatus, "close")
                        .update(),
                start.atZone(ZoneId.systemDefault()).toInstant());
        // 结束时间 → 开
        scheduler.schedule(() -> this.lambdaUpdate()
                        .eq(MeetingRooms::getRoomId, roomId)
                        .set(MeetingRooms::getStatus, "open")
                        .update(),
                end.atZone(ZoneId.systemDefault()).toInstant());
    }

    @Override
    public ResultVo<?> meetCount(Integer pageNum, Integer pageSize) {
        // 获取当前登录用户的角色代码
        List<String> roleCodes = this.sysUserMapper.selectRoleCodesByUserId(StpUtil.getLoginIdAsLong());
        PageHelper.startPage(pageNum, pageSize);
        List<MeetCount> meetCountList = new ArrayList<>();
        QueryWrapper<MeetingRooms> queryWrapper = new QueryWrapper<>();
        if (!roleCodes.contains("super_admin")) {
            HttpSession session = request.getSession();
            Long departmentId = (Long) session.getAttribute("departmentId");
            List<Long> roomIds = this.departmentMeetService.list(
                            new QueryWrapper<DepartmentMeet>().lambda()
                                    .eq(DepartmentMeet::getDepartmentId, departmentId)
                                    .select(DepartmentMeet::getRoomId)
                    ).stream()
                    .map(DepartmentMeet::getRoomId)
                    .collect(Collectors.toList());

            if (!roomIds.isEmpty()) {
                queryWrapper.in("room_id", roomIds);
            } else {
                // 如果没有会议室属于该部门，直接返回空结果
                PageInfo<MeetingRooms> emptyPageInfo = new PageInfo<>();
                emptyPageInfo.setList(Collections.emptyList());
                return ResultVo.success(emptyPageInfo);
            }
        }
        List<MeetingRooms> list = this.list(queryWrapper);
        for (MeetingRooms meetingRooms : list) {
            MeetCount meetCount = new MeetCount();
            meetCount.setRoomName(meetingRooms.getRoomName());
            long count = this.meetReservationService.count(new QueryWrapper<MeetReservation>().lambda().eq(MeetReservation::getRoomId, meetingRooms.getRoomId()));
            meetCount.setReservationNum(count);
            List<MeetReservation> list1 = this.meetReservationService.list(new QueryWrapper<MeetReservation>().lambda().eq(MeetReservation::getRoomId, meetingRooms.getRoomId()));
            List<Long> reservationIds = list1.stream()
                    .map(MeetReservation::getReservationId)
                    .toList();
            if (!reservationIds.isEmpty()) {
                // 查询这些预约记录的总时长
                double totalDuration = this.reservationMapper.selectList(
                                new QueryWrapper<Reservation>().in("reservation_id", reservationIds)
                        ).stream()
                        .mapToDouble(reservation -> {
                            long duration = Duration.between(
                                    reservation.getStartTime(), // 开始时间
                                    reservation.getEndTime() // 结束时间
                            ).getSeconds(); // 获取时间差（以秒为单位）
                            return duration / 3600.0; // 转换为小时
                        })
                        .sum();
                meetCount.setTotalDuration(totalDuration);
                Map<String, Long> timeFrequency = this.reservationMapper.selectList(
                                new QueryWrapper<Reservation>().in("reservation_id", reservationIds)
                        ).stream()
                        .collect(Collectors.groupingBy(
                                reservation -> reservation.getStartTime().toString() + "-" + reservation.getEndTime().toString(),
                                Collectors.counting()
                        ));
                // 找出所有出现次数最多的时间段
                long maxFrequency = timeFrequency.values().stream().max(Long::compare).orElse(0L);
                List<String> mostFrequentTimes = timeFrequency.entrySet().stream()
                        .filter(entry -> entry.getValue() == maxFrequency)
                        .map(Map.Entry::getKey)
                        .toList();
                meetCount.setMostFrequentDate(mostFrequentTimes);
            } else {
                meetCount.setTotalDuration(0);
                meetCount.setMostFrequentDate(Collections.emptyList());
            }

            meetCountList.add(meetCount);
        }
        PageInfo<MeetCount> meetCountPageInfo = new PageInfo<>(meetCountList);
        return ResultVo.success(meetCountPageInfo);
    }
}




